// SPDX-License-Identifier: Mulan PSL v2
/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This software is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

//! Request recording module
//!
//! This module provides functionality to record and replay Request messages in IPC communication,
//! primarily used for debugging, performance analysis, and regression testing.

// Protobuf generated types
pub mod types {
    pub mod xgpu_recorder {
        pub mod v1 {
            // Include generated protobuf code
            include!(concat!(env!("OUT_DIR"), "/xgpu.journal.v1.rs"));

            /// Record file magic number: 0x78475055 ("xGPU")  0x464F4F54 ("FOOT")
            pub const RECORD_FILE_MAGIC: u32 = 0x78475055;
            pub const FOOTER_MAGIC: u32 = 0x464F4F54;

            /// Record file version 1.0.0
            pub const RECORD_FILE_VERSION: RecorderVersion = RecorderVersion {
                major: 1,
                minor: 0,
                patch: Some(0),
            };

            use rustix::system;

            // Add convenience constructor for SystemContext
            impl SystemContext {
                pub fn new() -> Self {
                    Self {
                        hostname: system::uname().nodename().to_string_lossy().into_owned(),
                        process_id: std::process::id(),
                        process_name: std::env::current_exe()
                            .ok()
                            .and_then(|p| p.file_name().map(|n| n.to_string_lossy().to_string()))
                            .unwrap_or_else(|| "unknown".to_string()),
                        cuda_version: Some(String::from("12.2.140")),
                        driver_version: Some(String::from("535.104.05")),
                        toolkit_version: Some(String::from("12.2")),
                    }
                }
            }

            // Add convenience constructor for RecorderHeader
            impl RecorderHeader {
                pub fn new() -> Self {
                    Self {
                        magic: RECORD_FILE_MAGIC,
                        version: Some(RECORD_FILE_VERSION),
                        timestamp_ns: std::time::SystemTime::now()
                            .duration_since(std::time::UNIX_EPOCH)
                            .unwrap_or_default()
                            .as_nanos() as u64,
                        context: Some(SystemContext::new()),
                    }
                }
            }

            // Add convenience constructor for RecorderFooter
            impl RecorderFooter {
                pub fn new(total_requests: u64, sha256_digest: [u8; 32]) -> Self {
                    Self {
                        blocks: total_requests,
                        sha256_digest: sha256_digest.to_vec(),
                        magic: FOOTER_MAGIC,
                    }
                }
            }
        }
    }
}

mod format;
mod logger;
mod player;
use std::path::PathBuf;
use std::time::Instant;
use thiserror::Error;

/// Recorder error types
#[derive(Debug, Error)]
pub enum RecorderError {
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    #[error("serialization error: {0}")]
    Serialization(String),

    #[error("deserialization error: {0}")]
    Deserialization(String),

    #[error("file format error: {message}")]
    FormatError { message: String },

    #[error("buffer overflow: required {required}, available {available}")]
    BufferOverflow { required: usize, available: usize },

    #[error("invalid record at position {position}")]
    InvalidRecord { position: u64 },

    #[error("protobuf encoding error: {0}")]
    ProtobufEncoding(#[from] prost::EncodeError),

    #[error("protobuf decoding error: {0}")]
    ProtobufDecoding(#[from] prost::DecodeError),

    #[error("file corruption detected: {details}")]
    Corruption { details: String },
}

/// Recorder configuration (simplified version)
#[derive(Debug, Clone)]
pub struct RecorderConfig {
    /// Output file path
    pub output_path: PathBuf,
    /// Whether to enable compression
    pub compression: bool,
    /// block size
    pub block_size: usize,
    /// Maximum file size (bytes)
    pub max_file_size: u64,
    /// Sync interval (seconds)
    pub sync_interval_secs: u64,
    /// Whether to enable checksum verification
    pub checksum_enabled: bool,
}

impl Default for RecorderConfig {
    fn default() -> Self {
        Self {
            output_path: PathBuf::from("requests.rec"),
            compression: false,
            block_size: 128,
            max_file_size: 1024 * 1024 * 1024, // 1GB
            sync_interval_secs: 1,
            checksum_enabled: true,
        }
    }
}

/// Recorder statistics
#[derive(Debug, Default, Clone)]
pub struct RecorderStats {
    /// Total number of recorded requests
    pub total_requests: u64,
    /// Total bytes written
    pub total_bytes: u64,
    /// Flush count
    pub flush_count: u64,
    /// Last flush time
    pub last_flush: Option<Instant>,
}

// Re-export main types
pub use format::{RecordReader, RecordWriter};
pub use logger::RequestLogger;
pub use player::{RequestPlayer, RequestPlayerBuilder};

// Re-export protobuf generated types
pub use crate::types::xgpu_recorder::v1::{
    RecordBlock, RecordPayload, RecorderHeader, RecorderVersion, SystemContext, FOOTER_MAGIC,
    RECORD_FILE_MAGIC,
};

#[cfg(test)]
mod tests;
